home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / StandardDialog.java < prev    next >
Text File  |  1998-06-30  |  15KB  |  440 lines

  1. /*
  2.  * @(#)StandardDialog.java    1.23 01/28/98
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not disclose
  8.  * such Confidential Information and shall use it only in accordance with the
  9.  * terms of the license agreement you entered into with Sun.
  10.  * 
  11.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  12.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  13.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  14.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  15.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  16.  * ITS DERIVATIVES.
  17.  * 
  18.  */
  19.  
  20. package com.sun.java.swing;
  21.  
  22. import java.awt.*;
  23. import java.awt.event.*;
  24. import java.io.*;
  25.  
  26. import com.sun.java.swing.event.*;
  27. import com.sun.java.swing.plaf.*;
  28.  
  29. /**
  30.     A base class for a standard dialog box to request an object.
  31.     It can be used in either
  32.     a modal or non-modal fashion.  If it has any change listeners, change
  33.     Events will be sent to them
  34.     when the OK or Apply buttons are pressed.  If there are to be no item listeners
  35.     then the dialog box should be created with modal==true and the start
  36.     method will block until a new object is entered.
  37.     <p>
  38.     The standard pattern for doing a modal dialog box is:
  39.     <pre>Component c = <whatever is supposed to be inside the box>
  40.     StandardDialog d = new StandardDialog(parent, c, true);
  41.     d.setTitle("whatever");  // if needed
  42.     d.setDescription("paragraph to go at the top of the box"); // if needed
  43.     d.show();
  44.     value = c.getValue();
  45.     </pre>
  46.     <p>
  47.     In normal usage, the static convenience method ask that appears
  48.     in many standard Choosers is the easiest way to request objects:
  49.     <p><pre>
  50.      String c = StringChooser.ask(null, "What is your favorite color?",
  51.                  "purple", 40, null);
  52.     </pre><p>
  53.     @see FileChooser
  54.     @see ColorChooser
  55.     @see StringChooser
  56.     @see DateChooser
  57.     @see FontChooser
  58.     @author James Gosling
  59.  */
  60. public class StandardDialog extends Dialog {
  61.     // Needs much more flexible UI hooks
  62.     private Component body;
  63.     private int style;
  64.     private boolean locationUnknown = true;
  65.     private PaintRef backgroundPaint;
  66.     private GridBagConstraints cons;
  67.     private boolean canceled = false;
  68.     private static Font dialogFont = new Font ("Dialog", 0, 11);
  69.     private static Component defaultParent;
  70.     private AbstractButton[] buttonList;
  71.     private int buttonIndex = -1;
  72.     private Object description;
  73.     private UI ui;
  74.     private Icon descriptiveIcon;
  75.     private Component cparent;
  76.  
  77.     public static final int PlainStyle = 0;
  78.     public static final int QuestionStyle = 1;
  79.     public static final int InformStyle = 2;
  80.     public static final int WarnStyle = 3;
  81.     public static final int ErrorStyle = 4;
  82.  
  83.     /** Wraps a dialog box around a Component that implents
  84.      * the DialogBody interface. The Dialog box has OK, Cancel
  85.      * and Apply buttons that cause ItemSelected messages to
  86.      * be sent & the window to be closed as appropriate. */
  87.     public StandardDialog (Component parent, Component body, boolean modal) {
  88.     super(findFrame(parent), " ", false /* modal */ );
  89.     cparent = parent != null ? parent : defaultParent;
  90.     this.body = body;
  91.     setTitle(" ");
  92.     updateUI();
  93.     // UIManager.addUIChangeListener(this);
  94.     }
  95.     private static Frame findFrame(Component c) {
  96.     if (c == null)
  97.         c = defaultParent;
  98.     while (c != null && !(c instanceof Frame))
  99.         c = c.getParent();
  100.     if (defaultParent == null)
  101.         defaultParent = c;
  102.     return (Frame) c;
  103.     }
  104.  
  105.     /** Before the default constructor can be used, a default parent
  106.     has to be set up, either by a preceeding constructor invocation
  107.     with a non-null parent, or by an explicit call to setDefaultParent.
  108.     The dialog will be modal (there's an AWT bug that stops modal-ness
  109.     from being changed after the dialog is created) */
  110.     public StandardDialog () {
  111.     this(null, null, true);
  112.     }
  113.  
  114.     /** Convenience method to prompt for a button press.
  115.     @param fparent the parent frame for the dialog box.
  116.         fparent may be null if a default parent has
  117.         been established with StandardDialog
  118.     @param description a description string that will be shown
  119.         to the user to indicate what is being requested
  120.     @param style the style of the box (PlainStyle, QuestionStyle,
  121.         InformStyle, WarnStyle, ErrorStyle)
  122.     @param buttons the labels to appear on the buttons
  123.     @param target the ChangeListener that will be informed if
  124.             any button is hit
  125.     @return If target is null,
  126.         the dialog box will be modal and the method
  127.         will return the index of the button pressed,
  128.         or -1 if canceled.
  129.         Otherwise, the
  130.         dialog box is non-modal, the method returns null
  131.         immediatly, and the listener is informed when
  132.         appropriate.  The source of the change event will
  133.         be a StandardDialog on which you should call getButtonIndex.
  134.     @see StandardDialog
  135.      */
  136.     public static int ask(Component parent, String description, int style,
  137.                   Object buttons[],
  138.                   ChangeListener target) {
  139.     StandardDialog d = new StandardDialog (parent, null, target == null);
  140.     d.setDescription(description);
  141.     d.setStyle(style);
  142.     d.setButtonList(buttons);
  143.     if (target != null)
  144.         d.addChangeListener(target);
  145.     d.start();
  146.     if (target != null)
  147.         return -1;
  148.     d.setVisible(false);
  149.     d.dispose();
  150.     return d.isCanceled() ? -1 : d.getButtonIndex();
  151.     }
  152.  
  153.     /** This class keeps track of a default parent framem, which can be
  154.         set with this method.  When creating a StandardDialog, if the
  155.         parent parameter is null, this default parent will be used.  If
  156.     the default parent is not set explicitly, it will be implicitly
  157.     set if a StandardDialog is created with parent!=null.  It'll
  158.     make your life simpler if early on in your application (like when
  159.     you create your main application Frame) you set the default parent. */
  160.     public static void setDefaultParent(Component p) {
  161.     defaultParent = p;
  162.     }
  163.     /** Get the parent that this dialog box was created with.  A standard
  164.     dialog's parent may be an arbitrary Component, not just a Frame.
  165.     This Component is used to calculate the placement of the dialog box.
  166.     In contrast, getParent() will return the Frame that contains the
  167.     creation parent. */
  168.     public Component getCreationParent() {
  169.     return cparent;
  170.     }
  171.  
  172.     /** Set the style for the dialog box (PlainStyle, QuestionStyle,
  173.     InformStyle, WarnStyle, ErrorStyle) */
  174.     public void setStyle(int style) {
  175.     this.style = style;
  176.     }
  177.     public int getStyle() {
  178.     return style;
  179.     }
  180.     /** Set a descriptive icon to be used in the dialog box.  How it is
  181.     used depends on the particular style.  Optional. */
  182.     public void setDescriptiveIcon(Icon icon) {
  183.     descriptiveIcon = icon;
  184.     }
  185.     public Icon getDescriptiveIcon() {
  186.     return descriptiveIcon;
  187.     }
  188.  
  189.     /** A standard dialog may have a stack of descriptive information,
  190.     usually placed at the top.
  191.     @param d An array of descriptive information.  Objects which
  192.         are subclasses of Component will be used directly,
  193.         Arrays of Objects will be traversed and their elements
  194.         will be added,
  195.         Icons will be used in new JLabels, and
  196.         all others will be converted to strings via toString
  197.         and used in new JLabels.  Strings will be line wrapped
  198.         with paragraph breaks at newlines. */
  199.     public void setDescription(Object d) {
  200.     description = d;
  201.     }
  202.     /** Similar to setDescription except that instead of replacing
  203.         the whole list of descriptive information, it adds to the end. */
  204.     public void appendDescription(Object d) {
  205.     if (d != null)
  206.         if (description == null)
  207.         description = d;
  208.         else
  209.         description = new Object[] {
  210.             description, d
  211.         };
  212.     }
  213.     /** Similar to setDescription except that instead of replacing
  214.         the whole list of descriptive information, it adds before the
  215.     beginning. */
  216.     public void prependDescription(Object d) {
  217.     if (d != null)
  218.         if (description == null)
  219.         description = d;
  220.         else
  221.         description = new Object[] {
  222.             d, description
  223.         };
  224.     }
  225.     public Object getDescription() {
  226.     return description;
  227.     }
  228.  
  229.     /** A standard dialog may have an arbitrary list of buttons placed
  230.         at the bottom.
  231.     @param bl An array of buttons or button labels.  Objects which
  232.         are subclasses of AbstractButton will be used directly,
  233.         Icons will be used directly as labels on JButtons, and
  234.         all others will be converted to strings via toString
  235.         and used as the labels for new JButtons.  */
  236.     public void setButtonList(Object bl[]) {
  237.     AbstractButton[] b = new AbstractButton[bl.length];
  238.     for (int i = 0; i < bl.length; i++)
  239.         if (bl[i] instanceof AbstractButton)
  240.         b[i] = (AbstractButton) bl[i];
  241.         else if (bl[i] instanceof Icon)
  242.         b[i] = new JButton((Icon) bl[i]);
  243.         else
  244.         b[i] = new JButton(bl[i].toString());
  245.     buttonList = b;
  246.     }
  247.     public AbstractButton[] getButtonList() {
  248.     return buttonList;
  249.     }
  250.     /** When there is an arbitrary button list, the index of the button
  251.         that was pressed is available through getButtonIndex. */
  252.     public int getButtonIndex() {
  253.     return buttonIndex;
  254.     }
  255.     public void setButtonIndex(int bi) {
  256.     buttonIndex = bi;
  257.     }
  258.  
  259.     public void updateUI() {
  260.     UIFactory fac = UIManager.getDefaultFactory();
  261.     Color c = fac.getPaint("dialogforeground", "window_text").getColor();
  262.     if (c == SystemColor.window)
  263.         c = null;
  264.     setForeground(c != null ? c : SystemColor.windowText);
  265.     setBackgroundPaint(fac.getPaint("dialogbackground", "window"));
  266.     setFont(fac.getFont("dialogfont", "Dialog-11"));
  267.     // Can't use UIFactory.getUI since it demands ComponentUIs
  268.     String className = fac.getProperty("StandardDialogUI",
  269.               "com.sun.java.swing.basic.BasicStandardDialogUI");
  270.     try {
  271.         Class uiClass = Class.forName(className);
  272.         Class createUIArgClass = this.getClass();
  273.         java.lang.reflect.Method m = null;
  274.         do {
  275.         try {
  276.             m = uiClass.getMethod("createUI",
  277. /**INDENT** Error@277: Unbalanced parens */
  278.                       new Class[] {
  279.             createUIArgClass
  280. /**INDENT** Warning@279: Extra ) */
  281.             });
  282.         } catch(NoSuchMethodException nsme) {
  283.             // The target class doesn't define createUI(), try its
  284.             // parent.
  285.             createUIArgClass = createUIArgClass.getSuperclass();
  286.             if (createUIArgClass == null) {
  287.             System.err.println("createUI() not found in " +
  288.                        className);
  289.             return;
  290.             }
  291.         }
  292.         } while (m == null);
  293. /**INDENT** Error@291: Unbalanced parens */
  294.         ui = (UI) (m.invoke(null, new Object[] {
  295.         this
  296. /**INDENT** Warning@293: Extra ) */
  297. /**INDENT** Warning@293: Extra ) */
  298.         }));
  299.     } catch(Throwable cnf) {
  300.         cnf.printStackTrace();
  301.         return;
  302.     }
  303.     }
  304.     public void dispose() {
  305.     // UIManager.removeUIChangeListener(this);
  306.     // ui.uninstallUI(this);
  307.     super.dispose();
  308.     }
  309.  
  310.     private ChangeEvent changeEvent;
  311.     private EventListenerList listenerList = new EventListenerList();
  312.     public boolean hasChangeListener() {
  313.     Object [] o = listenerList.getListenerList();
  314.     if (o != null)
  315.         for (int i = o.length; (i -= 2) >= 0;)
  316.         if (o[i] == ChangeListener.class)
  317.             return true;
  318.     return false;
  319.     }
  320.  
  321.     /**
  322.      * Adds a ChangeListener to the button.
  323.      */
  324.     public void addChangeListener(ChangeListener l) {
  325.     listenerList.add(ChangeListener.class, l);
  326.     }
  327.  
  328.     /**
  329.      * Removes a ChangeListener from the button.
  330.      */
  331.     public void removeChangeListener(ChangeListener l) {
  332.     listenerList.remove(ChangeListener.class, l);
  333.     }
  334.     protected void fireStateChanged() {
  335.     // Guaranteed to return a non-null array
  336.     Object [] listeners = listenerList.getListenerList();
  337.     // Process the listeners last to first, notifying
  338.     // those that are interested in this event
  339.     for (int i = listeners.length - 2; i >= 0; i -= 2) {
  340.         if (listeners[i] == ChangeListener.class) {
  341.         // Lazily create the event:
  342.         if (changeEvent == null)
  343.             changeEvent = new ChangeEvent(body == null ?
  344.                           this :
  345.                           ((Component) (body)));
  346.         ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent);
  347.         }
  348.     }
  349.     }
  350.  
  351.     public synchronized void notifyChange() {
  352.     fireStateChanged();
  353.     notifyAll();
  354.     }
  355.  
  356.     /** Once the Dialog box is set up, start() pops the dialog box up
  357.         and begins the interaction.  If the dialog box is modal, start()
  358.         doesn't return until the interaction is complete.  Otherwise it
  359.         returns immediatly and the ChangeListeners will be notified when
  360.         a color is selected. */
  361.     public synchronized void start() {
  362.     ui.start(this);
  363.     if (hasChangeListener())
  364.         return;
  365.     try {
  366.     // can't use instanceof EventDispatchThread because the class isn't public
  367.     if (Thread.currentThread().getClass().getName().endsWith("EventDispatchThread")) {
  368.         EventQueue theQueue = getToolkit().getSystemEventQueue();
  369.         while (isVisible()) {
  370.         // This is essentially the body of EventDispatchThread
  371.         AWTEvent event = theQueue.getNextEvent();
  372.         Object src = event.getSource();
  373.         // can't call theQueue.dispatchEvent, so I pasted it's body here
  374.         /*if (event instanceof ActiveEvent) {
  375.             ((ActiveEvent) event).dispatch();
  376.         } else */ if (src instanceof Component) {
  377.             ((Component) src).dispatchEvent(event);
  378.         } else if (src instanceof MenuComponent) {
  379.             ((MenuComponent) src).dispatchEvent(event);
  380.         } else {
  381.             System.err.println("unable to dispatch event: " + event);
  382.         }
  383.         }
  384.     } else
  385.         while (isVisible())
  386.         wait();
  387.     } catch(InterruptedException e){}
  388.     }
  389.     /** true iff this dialog has been canceled by the user */
  390.     public boolean isCanceled() {
  391.     return canceled;
  392.     }
  393.     public void setCanceled(boolean b) {
  394.     canceled = b;
  395.     }
  396.     public Component getBody() {
  397.     return body;
  398.     }
  399.     public void setBackgroundPaint(PaintRef bkg) {
  400.     if (backgroundPaint != bkg) {
  401.         Color c = bkg.getColor();
  402.         setBackground(c != null ? c : SystemColor.window);
  403.         backgroundPaint = bkg;
  404.         repaint();
  405.     }
  406.     }
  407.     public PaintRef getBackgroundPaint() {
  408.     return backgroundPaint;
  409.     }
  410.  
  411.     public void paint(Graphics g) {
  412.     if (backgroundPaint != null && backgroundPaint.getTile() != null)
  413.         backgroundPaint.fill(g, this);
  414.     super.paint(g);
  415.     }
  416.     public void update(Graphics g) {
  417.     if (backgroundPaint != null)
  418.         backgroundPaint.fill(g, this);
  419.     super.paint(g);
  420.     }
  421.  
  422.     /** If the component that is the body of a StandardDialog implements to
  423.     OKcheck interface, then the isOK() method will be called after the
  424.     user has pressed the OK button to determine if it really is OK. */
  425.     public static interface OKcheck {
  426.     boolean isOK();
  427.     }
  428.  
  429.     /** If you want to implement a new user interface for standard dialogs,
  430.     this is the interface you have to implement. */
  431.     public static interface UI {
  432.     /** Once the Dialog box is set up, start() pops the dialog box up
  433.             and begins the interaction.  If the dialog box is modal, start()
  434.             doesn't return until the interaction is complete.  Otherwise it
  435.             returns immediatly and the ChangeListeners will be notified when
  436.             a color is selected. */
  437.     public void start(StandardDialog dlg);
  438.     }
  439. }
  440.